package main

import (
	"bytes"
	"compress/gzip"
	"crypto/tls"
	"crypto/x509"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/url"
	"os"
	"regexp"
	"strings"
	"sync"
	"time"

	"github.com/dsnet/compress/brotli"
	"github.com/elazarl/goproxy"
	"github.com/google/uuid"
	"github.com/gorilla/websocket"
	"github.com/spf13/viper"
)

var (
	proxy_addr                 = "localhost:11223"
	gateway_addr               = "localhost:11224"
	ws_listion_addr            = "localhost:11222"
	gateway_target_host        = "http://www.baidu.com"
	gateway_target_header_host = "www.baidu.com"
	target_ws_host             = "ws://www.baidu.com"
	cors_transform             = true
	cors_exclude_hosts         = []string{}
	gateway_server_url_map     = map[string]string{}
	metainfo_ch                chan MetaInfo
	mu                         sync.Mutex
	ws_mu                      sync.Mutex
	conn_list                  []*websocket.Conn
	upgrader                   = websocket.Upgrader{
		ReadBufferSize:  4096,
		WriteBufferSize: 4096,
		// 允许跨域访问
		CheckOrigin: func(r *http.Request) bool {
			return true
		},
	}
	cors_url_map_origin2uuid map[string]string
	cors_url_map_uuid2origin map[string]string
	request_body_map         map[*http.Request]string
)

type CertStorage struct {
	certs sync.Map
}

func (tcs *CertStorage) Fetch(hostname string, gen func() (*tls.Certificate, error)) (*tls.Certificate, error) {
	var cert tls.Certificate
	mu.Lock()
	defer mu.Unlock()
	icert, ok := tcs.certs.Load(hostname)
	if ok {
		cert = icert.(tls.Certificate)
	} else {
		certp, err := gen()
		if err != nil {
			return nil, err
		}
		// store as concrete implementation
		cert = *certp
		tcs.certs.Store(hostname, cert)
	}
	return &cert, nil
}

func NewCertStorage() *CertStorage {
	tcs := &CertStorage{}
	tcs.certs = sync.Map{}

	return tcs
}

func body_read(rc io.ReadCloser) []byte {
	if rc == nil {
		return []byte("")
	}
	content, err := io.ReadAll(rc)
	if err != nil {
		return []byte("")
	}

	return content
}

type TeeReadCloser struct {
	contentb []byte
	offset   int
}

func (t *TeeReadCloser) Read(b []byte) (int, error) {
	n := len(b)
	var right int
	if t.offset+n > len(t.contentb) {
		right = len(t.contentb)
	} else {
		right = t.offset + n
	}

	read_len := right - t.offset
	copy(b, t.contentb[t.offset:right])
	t.offset = right
	if right == len(t.contentb) {
		return read_len, io.EOF
	} else {
		return read_len, nil
	}
}

// Close attempts to close the reader and write. It returns an error if both
// failed to Close.
func (t *TeeReadCloser) Close() error {
	t.contentb = nil
	return nil
}

type MetaInfo struct {
	Url             string
	Request_method  string
	Status_code     int
	Remote_address  string
	Request_header  http.Header
	Request_body    string
	Response_header http.Header
	Response_body   string
}

func data_init() {
	metainfo_ch = make(chan MetaInfo, 32)
	cors_url_map_origin2uuid = make(map[string]string)
	cors_url_map_uuid2origin = make(map[string]string)
	request_body_map = make(map[*http.Request]string)
	// 启动服务器
	viper.SetConfigName("config") // 配置文件名称（不包含扩展名）
	viper.SetConfigType("toml")   // 配置文件格式
	viper.AddConfigPath(".")      // 查找配置文件所在的路径

	if err := viper.ReadInConfig(); err == nil {
		proxy_addr = viper.GetString("proxy_server.proxy_addr")
		gateway_addr = viper.GetString("gateway_server.gateway_addr")
		gateway_target_host = viper.GetString("gateway_server.gateway_target_host")
		gateway_target_header_host = strings.Split(gateway_target_host, "/")[2]
		target_ws_host = viper.GetString("gateway_server.target_ws_host")
		ws_listion_addr = viper.GetString("server.ws_listion_addr")
		cors_transform = viper.GetBool("gateway_server.cors_transform")
		cors_exclude_hosts = viper.GetStringSlice("gateway_server.cors_exclude_hosts")
		gateway_server_url_map = viper.GetStringMapString("gateway_server_url_map")
	}

	file1, err := os.Open("ca.crt")
	defer file1.Close()
	if err == nil {
		ca_bytes, err := io.ReadAll(file1)
		if err == nil {
			file2, err := os.Open("ca.key.pem")
			defer file2.Close()
			if err == nil {
				key_bytes, err := io.ReadAll(file2)
				if err == nil {
					caCert = ca_bytes
					caKey = key_bytes
					println("READ CUSTOM CERT SUCCESS.")
				}
			}
		}
	}

	println("**************************WEBSOCKET SERVER*****************************")
	println("The data-sniffed websocket server is running at " + ws_listion_addr + "/ws.\n")
	println("**************************PROXY SERVER*****************************")
	println("The proxy server is running at " + proxy_addr + ".\n")
	println("**************************GATEWAY SERVER*****************************")
	println("The gateway server is running at https://" + gateway_addr + ".")
	println("The gateway target server host is " + gateway_target_host + ".")
	println("***********************************************************************")
}

func main() {
	data_init()

	go boot_proxy()
	go boot_websocket()
	go boot_gateway()

	select {}
}

func boot_proxy() {
	setCA(caCert, caKey)
	proxy := goproxy.NewProxyHttpServer()
	proxy.Tr.TLSClientConfig.InsecureSkipVerify = true
	proxy.CertStore = NewCertStorage() //设置storage

	proxy.Verbose = false

	proxy.OnRequest().HandleConnect(goproxy.AlwaysMitm)
	proxy.OnRequest().DoFunc(collect_requests)
	proxy.OnResponse().DoFunc(collect_responses)

	log.Fatal(http.ListenAndServe(proxy_addr, proxy))
}

func boot_websocket() {
	go func() {
		for mi := range metainfo_ch {
			disable_conns := []*websocket.Conn{}
			ws_mu.Lock()
			for i := range conn_list {
				err := conn_list[i].WriteJSON(mi)
				if err != nil {
					log.Println("Error writing message:", err)
					disable_conns = append(disable_conns, conn_list[i])
				}
			}
			ws_mu.Unlock()

			for _, disable_conn := range disable_conns {
				remove_conn(disable_conn)
			}
		}
	}()

	http.HandleFunc("/ws", serveWs)

	var tlsClientSkipVerify = &tls.Config{InsecureSkipVerify: true}
	server := &http.Server{
		Addr:      ws_listion_addr,
		TLSConfig: tlsClientSkipVerify,
	}

	if err := server.ListenAndServe(); err != nil {
		log.Fatal("Proxy listenAndServe: ", err)
	}
}

func boot_gateway() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		backendURL := gateway_target_host + r.URL.String()
		path_items := strings.Split(strings.TrimPrefix(r.URL.String(), "/"), "/")

		host_map_enable := false
		for key := range gateway_server_url_map {
			// 指定映射优先级最高
			if strings.Contains(r.URL.String(), key) {
				backendURL = strings.TrimSuffix(gateway_server_url_map[key], "/") + r.URL.String()
				host_map_enable = true
				break
			}
		}

		origin_host, exists := cors_url_map_uuid2origin[path_items[0]]
		if !host_map_enable && exists {
			// 换源
			backendURL = strings.TrimSuffix(origin_host, "/") + "/" + strings.Join(path_items[1:], "/")
		}

		p, _ := url.Parse(backendURL)
		r.Header.Set("Referer", p.Scheme+"://"+p.Host)
		r.Header.Set("Host", p.Host)

		req, err := http.NewRequest(r.Method, backendURL, r.Body)
		req.Proto = r.Proto
		collect_requests(req, nil)
		if err != nil {
			http.Error(w, err.Error(), http.StatusBadGateway)
			return
		}

		// 转发请求头
		for header, values := range r.Header {
			for _, value := range values {
				req.Header.Add(header, value)
			}
		}

		if req.Header.Get("Upgrade") == "websocket" {
			build_ws(w, r)
			return
		}

		// 普通的HTTP/HTTPS请求
		client := &http.Client{
			Transport: &http.Transport{
				TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
			}}
		resp, err := client.Do(req)
		if resp != nil && req != nil {
			resp.Proto = req.Proto
		}
		if err != nil {
			fmt.Printf("!!!!!!!!!!!!!!Request server err %v\n", err)
			http.Error(w, err.Error(), http.StatusBadGateway)
			return
		}
		if resp != nil {
			resp.Request = req
		}
		resp = collect_responses(resp, nil)
		defer resp.Body.Close()

		// 转发响应头和状态码
		for header, values := range resp.Header {
			for _, value := range values {
				w.Header().Add(header, value)
			}
		}

		response_origin_body := body_read(resp.Body)
		response_body_s := response_origin_body
		if cors_transform {
			if strings.Contains(resp.Header.Get("Content-Type"), "text/html") ||
				strings.Contains(resp.Header.Get("Content-Type"), "text/css") ||
				strings.Contains(resp.Header.Get("Content-Type"), "javascript") ||
				strings.Contains(resp.Header.Get("Content-Type"), "json") {
				if resp.Header.Get("Content-Encoding") == "gzip" {
					response_origin_body_s := gzip_unzipped(response_origin_body)
					response_body_s = gzip_zipped(gateway_target_host_put(response_origin_body_s))
					w.Header().Del("Content-Length")
					w.Header().Set("Transfer-Encoding", "chunked")
				} else if resp.Header.Get("Content-Encoding") == "br" {
					response_origin_body_s := br_unzipped(response_origin_body)
					response_body_s = gzip_zipped(gateway_target_host_put(response_origin_body_s))
					w.Header().Set("Content-Encoding", "gzip")
					w.Header().Del("Content-Length")
					w.Header().Set("Transfer-Encoding", "chunked")
				} else {
					response_body_s = []byte(gateway_target_host_put(string(response_origin_body)))
				}
			}
		}

		resp.Body = &TeeReadCloser{contentb: response_body_s, offset: 0}

		w.WriteHeader(resp.StatusCode)
		// 转发响应体
		_, err = io.Copy(w, resp.Body)
		if err != nil {
			fmt.Printf("!!!!!!!!!!!!!!Response err %v\n", err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	})

	var tlsClientSkipVerify = &tls.Config{InsecureSkipVerify: true}
	server := &http.Server{
		Addr:      gateway_addr,
		TLSConfig: tlsClientSkipVerify,
	}

	if err := server.ListenAndServeTLS("ca.crt", "ca.key.pem"); err != nil {
		log.Fatal("Gateway ListenAndServeTLS: ", err)
	}
}

func str_arr_contains(arr []string, s string) bool {
	for _, a := range arr {
		if a == s {
			return true
		}
	}
	return false
}

func gateway_target_host_put(content string) string {
	if !cors_transform {
		return content
	}

	regexStr := `["|'][ \t]*(http[s]?:\/\/[0-9a-zA-Z\.\/\-_]+?)[ \t]*["|'|\/|\?]`
	regex := regexp.MustCompile(regexStr)

	s := regex.FindAllStringSubmatch(content, -1)

	ret_content := content
	for i := range s {
		origin_url := strings.TrimSpace(s[i][1])
		p, err := url.Parse(origin_url)
		if err != nil {
			fmt.Println("err", err)
			continue
		}

		if p.Host == gateway_target_host || str_arr_contains(cors_exclude_hosts, p.Host) {
			// 不用替换同源的
			continue
		}

		host := p.Scheme + "://" + p.Host
		host_id, exists := cors_url_map_origin2uuid[host]
		if !exists {
			host_id = uuid.New().String()
			cors_url_map_origin2uuid[host] = host_id
			cors_url_map_uuid2origin[host_id] = host
		}

		new_url := "https://" + gateway_addr + "/" + host_id + p.RequestURI()
		ret_content = strings.ReplaceAll(ret_content, origin_url, new_url)

	}
	return ret_content
}

func gzip_unzipped(b_content []byte) string {
	r, err := gzip.NewReader(bytes.NewBuffer(b_content))
	if err != nil {
		return ""
	}
	defer r.Close()

	// 读取解压后的数据
	unzippedData, err := io.ReadAll(r)
	if err != nil {
		return ""
	}

	return string(unzippedData)
}

func gzip_zipped(s_content string) []byte {
	var b bytes.Buffer
	gz := gzip.NewWriter(&b)
	if _, err := gz.Write([]byte(s_content)); err != nil {
		return []byte("")
	}
	if err := gz.Close(); err != nil {
		return []byte("")
	}
	return b.Bytes()
}

func br_unzipped(b_content []byte) string {
	rd, err := brotli.NewReader(bytes.NewReader(b_content), nil)
	unzippedData, err := io.ReadAll(rd)
	if err != nil {
		return ""
	}

	return string(unzippedData)
}

func build_ws(w http.ResponseWriter, r *http.Request) {
	conn1, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println("Websocket connection error :", err)
	}

	target_ws_server := target_ws_host + r.URL.String()
	target_ws_server = strings.TrimSuffix(target_ws_server, "/")

	conn2, _, err := websocket.DefaultDialer.Dial(target_ws_server, nil)
	if err != nil {
		log.Fatal(err)
	}

	defer conn1.Close()
	defer conn2.Close()

	wg := sync.WaitGroup{}
	wg.Add(2)

	go func() {
		defer wg.Done()
		for {
			_, p, err := conn2.ReadMessage()
			conn1.WriteMessage(websocket.TextMessage, p)
			if err != nil {
				log.Println("Server websocket read msg error :", err)
				return
			}
		}
	}()

	go func() {
		defer wg.Done()
		for {
			_, p, err := conn1.ReadMessage()
			conn2.WriteMessage(websocket.TextMessage, p)
			if err != nil {
				log.Println("Client websocket read msg error :", err)
				return
			}
		}
	}()

	wg.Wait()
}

func collect_requests(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
	request_origin_body_s := string(body_read(req.Body))
	req.Body = &TeeReadCloser{contentb: []byte(request_origin_body_s), offset: 0}
	mu.Lock()
	request_body_map[req] = request_origin_body_s
	mu.Unlock()

	go func() {
		select {
		case <-time.After(15000 * time.Millisecond):
			// 15秒后删除key
			mu.Lock()
			delete(request_body_map, req)
			mu.Unlock()
		}
	}()

	return req, nil
}

func collect_responses(resp *http.Response, ctx *goproxy.ProxyCtx) *http.Response {
	if resp != nil && resp.Header != nil {
		metainfo := MetaInfo{}
		metainfo.Url = resp.Request.URL.String()
		metainfo.Request_method = resp.Request.Method
		metainfo.Status_code = resp.StatusCode
		metainfo.Remote_address = resp.Request.RemoteAddr

		s, _ := json.Marshal(resp.Request.Header)
		json.Unmarshal(s, &metainfo.Request_header)
		mu.Lock()
		metainfo.Request_body = request_body_map[resp.Request]
		mu.Unlock()

		response_origin_body := body_read(resp.Body)
		response_origin_body_s := string(response_origin_body)
		if strings.Contains(resp.Header.Get("Content-Type"), "text/html") ||
			strings.Contains(resp.Header.Get("Content-Type"), "text/css") ||
			strings.Contains(resp.Header.Get("Content-Type"), "javascript") ||
			strings.Contains(resp.Header.Get("Content-Type"), "json") {
			if resp.Header.Get("Content-Encoding") == "gzip" {
				response_origin_body_s = gzip_unzipped(response_origin_body)
			} else if resp.Header.Get("Content-Encoding") == "br" {
				response_origin_body_s = br_unzipped(response_origin_body)
			} else {
				// do nothing
			}
		}
		metainfo.Response_body = response_origin_body_s
		s, _ = json.Marshal(resp.Header)
		json.Unmarshal(s, &metainfo.Response_header)
		metainfo_ch <- metainfo

		resp.Body = &TeeReadCloser{contentb: response_origin_body, offset: 0}
		return resp
	} else {
		return resp
	}
}

func remove_conn(conn *websocket.Conn) {
	ws_mu.Lock()
	defer ws_mu.Unlock()
	idx := -1
	for i := range conn_list {
		if conn_list[i] == conn {
			idx = i
			break
		}
	}

	if idx == -1 {
		return
	}

	conn_list = append(conn_list[:idx], conn_list[idx+1:]...)
}

func serveWs(w http.ResponseWriter, r *http.Request) {
	ws_mu.Lock()
	// 升级HTTP连接到WebSocket连接
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println("Failed to set websocket upgrade:", err)
		return
	}
	conn_list = append(conn_list, conn)
	ws_mu.Unlock()
}

var caCert = []byte(`-----BEGIN CERTIFICATE-----
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
-----END CERTIFICATE-----`)

var caKey = []byte(`-----BEGIN PRIVATE KEY-----
MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQDXSjsr3+5fBcis
zhV8l2P8QA3X1PtFMJqi0+4RpbiXB03HQTuGMclr1WDEujg3gtgmt7t4RY381VdK
/rYDqJ1/0bQxzaXZc76yrgW/nuvj5TNXaw2TSJLGdhciD1eBRttTEz8qUeum3h3r
1/gcPnrXyCZ5Di/Tgc6u6XGoeNUJRIkCOVyCZGXuIIzBdEyspp5NiMJaDklLudo6
t3E+6ZAoM/WloROW6rxYpNREzyOi5bbWNcXljFGH6nthfJURaXmtb6oIouKtyvfy
mNAy37wAJTInZh94O8kr58PJyFeJ9vn+BVUGrI3wDGpeROv4CDXTHpJK04sYEaOo
nRq0r2FkyrMVf6PrRyzrCLweaRdOZYfFainVN18NVo42EFY1RqmfW1ROVi+7eSee
yFDffsWgxHM2h741LlX92ia6O5cDMn4kQabZlReDgshJPnKla7U7PfDvb/Co14oh
5lVK4sl4xsz74yHNspUOkXR7FRbQNGdsio8y3jQwbW2rq0fzgYZfZOmpNsZxDIEE
HzlbDttYORL9OoiRm74FE9l0JN1P8g9CtMSSNToTdKY0iwTuPSTOFW7UkRsUNomF
YiGzd6QOfwYI37qAsWlEkpYllq5kt8fw4Ai5LjSSGj/jpjjx0sy2NOH+qOJqX6rx
+aWsIwZjf30A2Wi/bFNH3JA7+u3daQIDAQABAoICADRX6fcK5OvZfib1nCfErxyf
fj4hnE4AOTipilJkFnMx5WkypQRFipFbOcHa/NwSRfdz6HKfhpwYSrcDIsHU9yYi
mEsbkt1B1PWgdelW/EdWbJsufgh3NqhmAc3YKRBXZ+/U2CCz9jWF/4Rd6AcF8dwQ
37nDB0HHZ7cDLw0lA7bTIPSXebSCMH4rD83hNtsrT4XOYGKA4rU0pKht/WysYM5F
g84XUan5vH1Y5fss2Z87dq6yOEFNUm1XR1Q2dA/dsyXF5nNfFvnmRU6IdOZJm231
nTITFEepUYoJOYMP4Ki8kZ9/MGMFBSV9/0aYPz740A1ae3sR39mkQEQ4nkub8HOc
2kk1DUVJb6BtVQwSU3DbLU5llOjKbL/GyN9bS8FJW3ZPEBQyscVTFv/ph0/8iFP7
761tpchb1nyWKNDN/3YB0Ew/hxsBenrz4gPvLZXVUJSvIIEA9q1q6W8pjSBTDwWO
+PkoVsWHYcYbCjejZDRvJ9Z/DmBE3cY03/1qNqSFALQUGXlZXveTmQpHTO4K4TXC
P54xWyBDMDvSp11daGW2/mBNQRPjxzNJdtk+4AfC/zjuKCxKAOnpnPeDqEpo8CvY
xFS3I2z4GPCUkUuXvgHGF3FWZFOWbuQwv3ZfE49rPDr85i/gOQT3VfvvXLiODKn6
OqsEKwzhbOrthZ77uidhAoIBAQDxA8EpvVuYS15sw1u+oQJ3Sip3+67WcCYuLY3j
Ks7KpaXds2PH/19JcaVuU3/42VzS/XA9L1ZiNsvhZWykXl1RAnt1xtHQ78le7YsH
tSboGhNxaqdGpV7Sxkhz2N414OlYksWk0uMA1yNmRPv8GrR+2QiVBNOQEt26SYN4
HrMxk+kpvVla2AR2qHH/IWVPXjumbwiE84ppuW7pSgzebpH34WqCY39hrj4z/4J2
GH0N3Qjgoup5/PLjoHH6U4BLw4rrLon9bpDhCOQCEA7/U2aYj8n0hwOOBJkTHC7/
gX+5A9Ah2HGW1JGXD7/Odkpbf3gFqbVVurC5fC7dXvnlFKQ1AoIBAQDkrQPScE7c
RQioWegcQFO6md1Zh5nXcghbrs0P2Mc3uMou5cnEjsPlerzWYyULXURrwxBFbfdq
vyTqXotWHdE1BdQMsmS/mcIzEdpwbQSe8bh230l0hYHW5fDbIxkYf6tzQ38ApaUH
SjeyAi2+iMFUo9xQNF1CyWQjJvKp7A8fgPPK0BF57Af4ISkDq0QfUepLSLl5LxPh
97/cK3iMzoLc+BkcSC8/+d6wV3o9Y95axaJ7HfEPay90J0xmCpNrtwzlncMDdIS5
TohietbbEK2ILUStZl1xGwMnyq43UGu5x0GiTCY9YvJjNnje7IwulrJMOArqHg37
6bJbweknJlLlAoIBAHMFtLEj4svK5HSJw4Y1t0SRC7WZUvaaLU6KhRWuP2StK3yj
+XHgaWxWpXoCtadgrREwzNkWd2aF+kVGr1O+iVB5G8y4pzfMyFDakyiJhtjsYO0W
1mA72gZDhR5smJgkD5kq6tJfpuCmzAkp0Qye/hcvow3jcMhoiJM4NFsmY6S8j2FR
MYzOXUr31vfIy13WfidPBETXKe6NBeamZX/eSyF+3eL+czN+Ace1IGEWDNCJ9Yun
lLnFQ3HpB5xNL4R4/RqCam6dztzm7lIhsdaeye7zaJGfwc2MWjWplLBx8C+vJyyP
7J3sMtNiO8rf31rNec1SEe2pHGBZaNBTXHW8pSUCggEAETWECB4zkRgQ4rqBYT7m
DjDuG4K87R3Dy0KIZBzoQSVC8eyRFp232Fk4RNoJO6W1NHbljpQL/piL6qdazQxJ
ZjgeESaLtm+X0cgSLEvIAT4np6p+GKrDbqy3R4aIqPNSr8XwlNfiZ34KWvcXAjPA
eOIr/k0yh4goZQzVTjxZlwFZV3X5GrfMkbvNHl2RLto3S5sZeik00diXM7aBx/by
mjaBjUNRavse6x5qMJyHa0VcSO+j6IkkdRVQBo3dMkoASndo6aWnJ1rloKOl7659
oLXnaTU+6vghcKksGzWOJdj8833PkucTXqwGxKAAnLDykhHVoHDKlJ6tsYISTcPw
kQKCAQAVPYYwtr/YTMzLOnudk3gUd5t3qoFmWs9+bhAxOk1YgmaH7+xXTP1w3vPr
QXc5pMOGwQM+XE6e1iw7gRLV651FQz7yjZCAqN3kOZwfiF8Yg3N9ACX95xT6MC03
aB7oBXnX/6n0mc3CfNc2YvN4/l6JmWnPas7mluyUQUok5NffIMKSF6Sz3CT4wVhJ
0lfRbog/DFMG8CZRWPoezr82xw+dRoogM6p+GWtsRfBeXM6/QST67CqQwrkuTiiB
YiVF/INjcYGMdAke8FwRJgfYq5TH8euGi1epALtZ8ZtwzdKzMleIvN8dqaqffnwh
VdlIbnA3yN3mIeYt/HCFVYZL3sMI
-----END PRIVATE KEY-----`)

func setCA(caCert, caKey []byte) error {
	goproxyCa, err := tls.X509KeyPair(caCert, caKey)
	if err != nil {
		return err
	}
	if goproxyCa.Leaf, err = x509.ParseCertificate(goproxyCa.Certificate[0]); err != nil {
		return err
	}
	goproxy.GoproxyCa = goproxyCa
	goproxy.OkConnect = &goproxy.ConnectAction{Action: goproxy.ConnectAccept, TLSConfig: goproxy.TLSConfigFromCA(&goproxyCa)}
	goproxy.MitmConnect = &goproxy.ConnectAction{Action: goproxy.ConnectMitm, TLSConfig: goproxy.TLSConfigFromCA(&goproxyCa)}
	goproxy.HTTPMitmConnect = &goproxy.ConnectAction{Action: goproxy.ConnectHTTPMitm, TLSConfig: goproxy.TLSConfigFromCA(&goproxyCa)}
	goproxy.RejectConnect = &goproxy.ConnectAction{Action: goproxy.ConnectReject, TLSConfig: goproxy.TLSConfigFromCA(&goproxyCa)}
	return nil
}
